#include <iostream>
#include <vector>
#include <string>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task_work.hpp"
enum
{
    OK = 0,
    PIPEERROR,
    FORKERROR
};
class Channel
{
public:
    Channel(int wfd, pid_t who) : _wfd(wfd), _who(who)
    {
        _name = std::to_string(wfd);
        _name += "->";
        _name += std::to_string(_who);
    }
    void Send(int num) // 管道写端发送任务码
    {
        ::write(_wfd, &num, sizeof(num));
    }
    std::string GetName()
    {
        return _name;
    }
    void Close() // 关闭管道的写端
    {
        ::close(_wfd);
    }
    pid_t Getpid()
    {
        return _who;
    }
    ~Channel()
    {
    }

private:
    int _wfd;
    pid_t _who;
    std::string _name;
};

int InitPool(int num_processes, std::vector<Channel> &channels, work_t work) // 第三函数对象实现回调
{
    for (int i = 0; i < num_processes; i++)
    {
        int pipefd[2] = {0};
        int n = ::pipe(pipefd); // 创建管道
        if (n < 0)
        {
            std::cout << "Pipe error" << std::endl;
            return PIPEERROR;
        }
        pid_t pid = ::fork();
        if (pid < 0)
        {
            std::cout << "Fork error" << std::endl;
            return FORKERROR;
        }
        else if (pid == 0)
        {
            ::close(pipefd[1]);   // 子进程读，关闭写
            ::dup2(pipefd[0], 0); // 管道读段重定向到stdin中;默认从标准输入读取,这样执行work函数时不需要传递读取的文件描述符pipefd[0];
            work();
            ::exit(0);
        }
        else
        {
            ::close(pipefd[0]); // 父进程写，关闭读
            // Channel ch(pipefd[1],pid);
            // channels.push_back(ch);
            channels.emplace_back(pipefd[1], pid); // 保存每个管道的写端以及对应的子进程
        }
    }
    return OK;
}
void Work()
{
    while (true) // 子进程不断的读
    {
        int num = 0;
        int n = ::read(0, &num, sizeof(num));
        if (n == sizeof(num))
        {
            tsm.Excubte_Tasks(num);
        }
        else if (n == 0) // 写端关闭，读到文件末尾，为0
        {
            std::cout << getpid() << " quit" << std::endl;
            break;
        }
    }
}
void debug1(std::vector<Channel> &channels)
{
    for (auto &ch : channels)
        std::cout << ch.GetName() << std::endl;
}
void DispatchTasks(std::vector<Channel> &channels) // 分发任务
{
    int sum = 10;
    int who = 0;
    while (sum--)
    {
        int task_num = tsm.Select_Tasks(); // 选择任务码

        std::cout << "-------------" << std::endl;
        std::cout << "--执行任务--" << sum << std::endl;
        std::cout << "-------------" << std::endl;
        who %= channels.size();
        Channel &ch = channels[who++];
        std::cout << ch.GetName() << std::endl;
        std::cout << task_num << std::endl;
        ch.Send(task_num);
        ::sleep(1);
    }
}
void CleanPool(std::vector<Channel> &channels)
{
    for (auto &ch : channels) // 关闭每个管道的写端
        ch.Close();
    for (auto &ch : channels) // 回收每个管道对应的子进程
    {
        int rid = ::waitpid(ch.Getpid(), nullptr, 0); // 阻塞式等待
        if (rid > 0)
            std::cout <<rid<< " wait sucess..." << std::endl;
    }
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usage: " << argv[0] << " num_processes" << std::endl; // 可执行程序后面接数字，表示进程数
        return -1;
    }
    int num_processes = std::stoi(argv[1]); // 获取进程数
    std::vector<Channel> channels;          // 管道数组

    // 1、初始化进程池
    int ret = InitPool(num_processes, channels, Work);
    if (ret != OK)
        return ret;
    // debug1(channels);
    // 2、分发任务
    DispatchTasks(channels);
    // 3、退出进程池
    CleanPool(channels);
    return 0;
}